package cn.anlucky.admin.generation.service.impl;

import cn.anlucky.admin.generation.config.GenerationConfig;
import cn.anlucky.admin.generation.povo.GenerationPo;
import cn.anlucky.admin.generation.service.GenerationCodeService;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

/**
 * 代码生成服务实现类
 */
public class GenerationCodeServiceImpl implements GenerationCodeService {

    private final GenerationConfig generationConfig;


    public GenerationCodeServiceImpl(GenerationPo generationPo) {
        this.generationConfig = new GenerationConfig(generationPo);
    }


    /**
     * 生成代码到本机的指定位置
     *
     * @param parentPackage 父包名
     * @param moduleName    模块名称
     * @param tableNames    表名
     */
    @Override
    public void generateCode(String parentPackage, String moduleName, List<String> tableNames) {
        ConfigBuilder configBuilder = generationConfig.getConfigBuilder(tableNames, parentPackage, moduleName);
        VelocityTemplateEngine templateEngine = new VelocityTemplateEngine().init(configBuilder);
        ((AbstractTemplateEngine) templateEngine).setConfigBuilder(configBuilder);
        ((AbstractTemplateEngine) templateEngine).init(configBuilder).batchOutput().open();
        System.out.println("代码生成成功,文件输出位置" + configBuilder.getGlobalConfig().getOutputDir());
    }

    /**
     * 生成代码
     *
     * @param parentPackage 父包名
     * @param moduleName    模块名称
     * @param tableNames    表名
     */
    @Override
    public Map<String, String> previewCode(String parentPackage, String moduleName, List<String> tableNames) {
        HashMap<String, String> map = new HashMap<>();
        ConfigBuilder configBuilder = generationConfig.getConfigBuilder(tableNames, parentPackage, moduleName);
        VelocityTemplateEngine templateEngine = new VelocityTemplateEngine().init(configBuilder);
        configBuilder.getTableInfoList().forEach(tableInfo -> {
            // 生成自定义模板代码
            Map<String, Object> objectMap = templateEngine.getObjectMap(configBuilder, tableInfo);
            Optional.ofNullable(configBuilder.getInjectionConfig()).ifPresent(t -> {
                // 添加自定义属性
                t.beforeOutputFile(tableInfo, objectMap);
                // 添加自定义属性
                objectMap.putAll(Objects.requireNonNull(configBuilder.getInjectionConfig()).getCustomMap());
                t.getCustomFiles().forEach(t1 -> {
                    try {
                        String writer = templateEngine.writer(objectMap, tableInfo.getEntityName(), readFileContent(t1.getTemplatePath()));
                        map.put(t1.getPackageName(), writer);
                    } catch (Exception e) {
                        e.printStackTrace();
                        throw new RuntimeException("模板：" + t1.getTemplatePath() + "生成代码预览报错：" + e.getMessage());
                    }
                });
            });

            // 生成后端代码
            String entityString = previewCodeEntity(templateEngine, configBuilder, tableInfo);
            String mapperString = previewCodeMapper(templateEngine, configBuilder, tableInfo);
            String mapperXmlString = previewCodeMapperXML(templateEngine, configBuilder, tableInfo);
            String serviceString = previewCodeService(templateEngine, configBuilder, tableInfo);
            String serviceImplString = previewCodeServiceImpl(templateEngine, configBuilder, tableInfo);
            String controllerString = previewCodeController(templateEngine, configBuilder, tableInfo);

            map.put(GenerationPo.ENTITY, entityString);
            map.put(GenerationPo.MAPPER, mapperString);
            map.put(GenerationPo.MAPPER_XML, mapperXmlString);
            map.put(GenerationPo.SERVICE, serviceString);
            map.put(GenerationPo.SERVICE_IMPL, serviceImplString);
            map.put(GenerationPo.CONTROLLER, controllerString);

        });
        return map;
    }

    /**
     * 预览Entity代码
     *
     * @param templateEngine
     * @param configBuilder
     * @param tableInfo
     * @return
     */
    private String previewCodeEntity(VelocityTemplateEngine templateEngine, ConfigBuilder configBuilder, TableInfo tableInfo) {
        // 渲染对象
        Map<String, Object> objectMap = templateEngine.getObjectMap(configBuilder, tableInfo);
        // 实体名称
        String entityName = tableInfo.getEntityName();
        // 模板位置
        String templatePath = templateEngine.templateFilePath(configBuilder.getStrategyConfig().entity().getJavaTemplate());
        String templateString = null;
        try {
            templateString = templateEngine.writer(objectMap, entityName, readFileContent(templatePath));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("模板：" + templatePath + "生成代码预览报错：" + e.getMessage());
        }
        return templateString;
    }

    /**
     * 预览Mapper代码
     *
     * @param templateEngine
     * @param configBuilder
     * @param tableInfo
     * @return
     */
    private String previewCodeMapper(VelocityTemplateEngine templateEngine, ConfigBuilder configBuilder, TableInfo tableInfo) {
        // 渲染对象
        Map<String, Object> objectMap = templateEngine.getObjectMap(configBuilder, tableInfo);
        // 实体名称
        String mapperName = tableInfo.getMapperName();
        // 模板位置
        String templatePath = templateEngine.templateFilePath(configBuilder.getStrategyConfig().mapper().getMapperTemplatePath());
        String templateString = null;
        try {
            templateString = templateEngine.writer(objectMap, mapperName, readFileContent(templatePath));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("模板：" + templatePath + "生成代码预览报错：" + e.getMessage());
        }
        return templateString;
    }

    /**
     * 预览MapperXML代码
     *
     * @param templateEngine
     * @param configBuilder
     * @param tableInfo
     * @return
     */
    private String previewCodeMapperXML(VelocityTemplateEngine templateEngine, ConfigBuilder configBuilder, TableInfo tableInfo) {
        // 渲染对象
        Map<String, Object> objectMap = templateEngine.getObjectMap(configBuilder, tableInfo);
        // 实体名称
        String mapperXmlName = tableInfo.getMapperName();
        // 模板位置
        String templatePath = templateEngine.templateFilePath(configBuilder.getStrategyConfig().mapper().getMapperXmlTemplatePath());
        String templateString = null;
        try {
            templateString = templateEngine.writer(objectMap, mapperXmlName, readFileContent(templatePath));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("模板：" + templatePath + "生成代码预览报错：" + e.getMessage());
        }
        return templateString;
    }

    /**
     * 预览Service代码
     *
     * @param templateEngine
     * @param configBuilder
     * @param tableInfo
     * @return
     */
    private String previewCodeService(VelocityTemplateEngine templateEngine, ConfigBuilder configBuilder, TableInfo tableInfo) {
        // 渲染对象
        Map<String, Object> objectMap = templateEngine.getObjectMap(configBuilder, tableInfo);
        // 实体名称
        String serviceName = tableInfo.getServiceName();
        // 模板位置
        String templatePath = templateEngine.templateFilePath(configBuilder.getStrategyConfig().service().getServiceTemplate());
        String templateString = null;
        try {
            templateString = templateEngine.writer(objectMap, serviceName, readFileContent(templatePath));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("模板：" + templatePath + "生成代码预览报错：" + e.getMessage());
        }
        return templateString;
    }

    /**
     * 预览ServiceImpl代码
     *
     * @param templateEngine
     * @param configBuilder
     * @param tableInfo
     * @return
     */
    private String previewCodeServiceImpl(VelocityTemplateEngine templateEngine, ConfigBuilder configBuilder, TableInfo tableInfo) {
        // 渲染对象
        Map<String, Object> objectMap = templateEngine.getObjectMap(configBuilder, tableInfo);
        // 实体名称
        String serviceImplName = tableInfo.getServiceImplName();
        // 模板位置
        String templatePath = templateEngine.templateFilePath(configBuilder.getStrategyConfig().service().getServiceImplTemplate());
        String templateString = null;
        try {
            templateString = templateEngine.writer(objectMap, serviceImplName, readFileContent(templatePath));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("模板：" + templatePath + "生成代码预览报错：" + e.getMessage());
        }
        return templateString;
    }

    /**
     * 预览Controller代码
     *
     * @param templateEngine
     * @param configBuilder
     * @param tableInfo
     * @return
     */
    private String previewCodeController(VelocityTemplateEngine templateEngine, ConfigBuilder configBuilder, TableInfo tableInfo) {
        // 渲染对象
        Map<String, Object> objectMap = templateEngine.getObjectMap(configBuilder, tableInfo);
        // 实体名称
        String controllerName = tableInfo.getControllerName();
        // 模板位置
        String templatePath = templateEngine.templateFilePath(configBuilder.getStrategyConfig().controller().getTemplatePath());
        String templateString = null;
        try {
            templateString = templateEngine.writer(objectMap, controllerName, readFileContent(templatePath));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("模板：" + templatePath + "生成代码预览报错：" + e.getMessage());
        }
        return templateString;
    }

    /**
     * 读取文件内容
     *
     * @param fileName 文件名
     * @return 文件内容
     */
    private String readFileContent(String fileName) {
        if (fileName == null || fileName.trim().isEmpty()) {
            throw new RuntimeException("文件名不能为空");
        }
        StringBuilder content = new StringBuilder();
        ClassPathResource resource = new ClassPathResource(fileName);
        if (!resource.exists()) {
            throw new RuntimeException("文件 " + fileName + " 不存在");
        }
        try (InputStream inputStream = resource.getInputStream();
             InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
             BufferedReader reader = new BufferedReader(inputStreamReader)) {
            String line;
            boolean isFirstLine = true;
            while ((line = reader.readLine()) != null) {
                if (isFirstLine) {
                    isFirstLine = false;
                } else {
                    content.append("\n");
                }
                content.append(line);
            }
        } catch (IOException e) {
            throw new RuntimeException("读取文件 " + fileName + " 时发生错误" + e.getMessage());
        }
        return content.toString();
    }

}
